package com.xiaoma.pattern.proxy;

import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * https://blog.csdn.net/bu2_int/article/details/60150319
 * https://stackoverflow.com/questions/22930195/understanding-proxy-arguments-of-the-invoke-method-of-java-lang-reflect-invoca
 * https://paste.ubuntu.com/26104595/
 * @author xiaomacdut
 * @date 2020年3月2日 下午12:36:59
 */
public class Main{
    
    private interface Account{
        
        public Account deposit(double value);
        
        public double getBalance();
    }
    
    private class ExampleInvocationHandler implements InvocationHandler{
        
        private double balance;
        
        @Override
        public Object invoke(Object proxy, Method method, Object [] args) throws Throwable{
            
            // simplified method checks, would need to check the parameter count and types too
            if("deposit".equals(method.getName())){
                Double value = (Double) args[0];
                System.out.println("deposit: " + value);
                balance += value;
                // 那为什么不返回this，而是返回proxy对象呢？
                // 因为this对象的类型是ExampleInvocationHandler，而不是代理类$Proxy0
                return proxy; // here we use the proxy to return 'this'
            }
            if("getBalance".equals(method.getName())){
                return balance;
            }
            return null;
        }
    }
    
    public static void main(String [] args){
        new Main();
    }
    
    Main(){
        Account account = (Account) Proxy.newProxyInstance(getClass().getClassLoader(),
                new Class[]{Account.class, Serializable.class}, new ExampleInvocationHandler());
        
        // method chaining for the win!
        account.deposit(5000).deposit(4000).deposit(-2500);
        System.out.println("Balance: " + account.getBalance());
        
    }
    
}
